import { getClassDefaultValue, isNull } from '@gowiny/js-utils';
import { createDecorator } from '../core/helpers'

export interface InjectOptions{
    from?: string | symbol;
    default?: unknown;
}

declare type ObjectInjectOptions = Record<string | symbol, string | symbol | {
    from?: string | symbol;
    default?: unknown;
}>;

function create(params:InjectOptions,target: any, propertyKey: string,descriptor?: PropertyDescriptor){
    createDecorator(function (ctx, key) {
        const options = ctx.options
        if(!options.inject){
            options.inject = {}
        }
        const data = Object.assign({from:key},params)
        if(isNull(data.default)){
            if(descriptor?.value){
                data.default = function(){ return descriptor.value }
            }else{
                data.default = getClassDefaultValue(ctx.classType,key)
            }
        }
        const inject:ObjectInjectOptions = options.inject as ObjectInjectOptions
        inject[key] = data
        ctx.excludeKeys.push(key)
    })(target, propertyKey);
}

export function Inject(params:symbol):any;
export function Inject(params:string):any;
export function Inject(params:InjectOptions):any;
export function Inject(target: any, propertyKey: string):void;
export function Inject(target: any, propertyKey: string,descriptor: PropertyDescriptor):void;
export function Inject(target: any, propertyKey="",descriptor?: PropertyDescriptor):void | any{
    if(propertyKey){
        create({from:propertyKey},target,propertyKey,descriptor)
    }else{
        const targetType = typeof target
        const params:InjectOptions =  targetType === 'string' || targetType === 'symbol' ? {from:target} : target as InjectOptions
        return function (target: any, propertyKey: string,descriptor?: PropertyDescriptor) {
            create(params,target,propertyKey,descriptor)
        };
    }
}
